package ru.chaykin.rendering;

import java.nio.ByteBuffer;

import ru.chaykin.load.parse.MIFParser;
import ru.chaykin.primitives.Circle;
import ru.chaykin.viewobject.ViewObject;
import ru.chaykin.viewobject.texture.Texture;
import ru.chaykin.viewobject.texture.TextureFactory;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;

public class CullingTextThread extends CullingThread implements ITexConsts {
	
	public static final short TEX_BUFF_SIZE = 16;
	public static volatile ViewObject[] textureBuff = new ViewObject[TEX_BUFF_SIZE];
	
	public void run() {
		Log.d(getClass().getName(), "Thread started");
		boolean isnNull = false;
		while (isActive) {	//Ищем и "переискиваем" (т.к. область отображения меняется пользователем)
			for (int i = 0; i < TEX_BUFF_SIZE; i++) {
				synchronized(textureBuff) {// Вынесено отдельно и добавлена isnNull для минимизации времени в мониторе
					if (textureBuff[i] != null) {	//В буфере уже что-то есть...
						isnNull = true;
						bCircle = textureBuff[i].getBoundCircle(); //Узнаем область, в которой находится объект...
					} else {
						isnNull = false;
					}
				}
				if (isnNull) { //В буфере уже что-то есть...
					if (!bCircle.in(ra))  //Объект больше не попадает в область видимости 
						fillTexBuff(i); //Читаем новый из файла
				}
				else 
					fillTexBuff(i); //Читаем новый объект из файла
			}
		}
		Log.d(getClass().getName(), "Thread stoped");
	}
	
	/**
	 * Заполняет буфер текстур из отображенного на память файла
	 * @param index	- индекс, по которому заполняется буфер
	 */
	private final void fillTexBuff(int index) {
		do { // Пытаемся найти в файле объект, который попадает в область видимости
			synchronized(MIFParser.mappedIndexTextBuff) {
				indTotalNum = MIFParser.mappedIndexTextBuff.position();	//Размер файла в байтах (т. к. загрузка происходит асинхронно, то в процессе работы потока размер может увеличиваться)
			}
			if (indTotalNum == 0)
				return;
			if (indNum > indTotalNum - IND_TEXT_ROW_SIZE)	//Если достигли конца файла, то начнем все сначала
				indNum = 0;
			synchronized(MIFParser.mappedIndexTextBuff) {
				float x = MIFParser.mappedIndexTextBuff.getFloat(indNum + CIRCLE_X);
				float y = MIFParser.mappedIndexTextBuff.getFloat(indNum + CIRCLE_Y);
				float r = MIFParser.mappedIndexTextBuff.getFloat(indNum + CIRCLE_RAD);
				bCircle = new Circle(x, y, r);
				offset = (int) MIFParser.mappedIndexTextBuff.getFloat(indNum + TEXT_OFFSET);	//Узнаем, где лежит нужный нам объект (смещение)
				length = (int) MIFParser.mappedIndexTextBuff.getFloat(indNum + TEXT_LENGTH);
			}
			
			foundVisibleObject = false;
			if (bCircle.in(ra) && length > 0) {//Объект есть и он попал в поле зрения
				boolean hasDouble = false;
				boolean notNull = true;
				Circle circle;
				for (int i = 0; i < TEX_BUFF_SIZE; i++) {
					synchronized(textureBuff) {
						notNull = (textureBuff[i] != null);
					}
					if (i != index && notNull)	{ //Сам себе, конечно, дубль, но это не в счет
						synchronized(textureBuff) {
							circle = textureBuff[i].getBoundCircle();
						}
						//Если объемлющие окружности совпадают, значит, это тот же объект, не будем его еще раз добавлять
						if (bCircle.equals(circle)) { 
							hasDouble = true;
							break;
						}
					}
				}
				if (!hasDouble)
					prepareTex(index);
			}
			indNum += IND_TEXT_ROW_SIZE; // Переходим к следующему объекту
		} while (!foundVisibleObject && isActive);	//Ищем, пока не найдем. (Если не найдем, то не найдем, все равно в потоке же. Как только подходящие объекты объявятся, выйдем из цикла :)
	}

	private final void prepareTex(int index) {
		ByteBuffer fb = ByteBuffer.wrap(getTextDataFromMappedBuff());
		float[] rect = new float[RECT_BUFF_SIZE];	//На этом прямоугольнике будет текстура с текстом
		rect[X0] = fb.getFloat(X0_BUFF);
		rect[Y0] = fb.getFloat(Y0_BUFF);
		rect[X1] = fb.getFloat(X1_BUFF);
		rect[Y1] = fb.getFloat(Y1_BUFF);
		int color = (int) fb.getFloat(COLOR_BUFF);
		float alpha = fb.getFloat(ANGLE_BUFF);
		int midIndex = (int) fb.getFloat(MID_IND_BUFF);
		String text = new String(fb.array(), TEXT_CONST_PART_ROW_SIZE, fb.array().length - TEXT_CONST_PART_ROW_SIZE);
		
		Bitmap bm = Bitmap.createBitmap(Texture.TEX_PIXEL_WIDTH, Texture.TEX_PIXEL_HEIGHT, Bitmap.Config.ARGB_8888);
		bm.eraseColor(TRANSPARENCY_BACKGROUND);
		Canvas canvas = new Canvas(bm);
		
		Paint textPaint = new Paint();
		textPaint.setTextSize(FONT_SIZE);
		textPaint.setAntiAlias(true);
		textPaint.setColor(TRANSPARENCY_TEXT | color);
		
		canvas.rotate(-alpha, Texture.TEX_PIXEL_WIDTH / 2, Texture.TEX_PIXEL_HEIGHT / 2);
		float textPixelSize = textPaint.measureText(text);
		canvas.drawText(text, Texture.TEX_PIXEL_WIDTH / 2 - textPixelSize / 2, Texture.TEX_PIXEL_HEIGHT / 2 + 12, textPaint);
		
		
		float realTextWidth = Math.abs(rect[X0] - rect[X1]);
		float lambda = Texture.TEX_PIXEL_WIDTH / textPixelSize;
		
		rect[X0] = (rect[X0] + rect[X1]) / 2 - lambda * realTextWidth / 2 ;
		rect[Y0] = (rect[Y0] + rect[Y1]) / 2 - lambda * realTextWidth / 2 ;
		rect[X1] = rect[X0] + lambda * realTextWidth;
		rect[Y1] = rect[Y0];
		
		rect[X2] = rect[X0];
		rect[Y2] = rect[Y1] + lambda * realTextWidth;
		rect[X3] = rect[X1];
		rect[Y3] = rect[Y2];
		
		synchronized(textureBuff) {
			textureBuff[index] = TextureFactory.genTexture(bCircle, index, midIndex, bm, rect);
		}
		foundVisibleObject = true;
	}
	
	private final byte[] getTextDataFromMappedBuff() {
		int prevPos;
		byte[] btmp = new byte[length];
		synchronized(MIFParser.mappedTextBuff) {
			prevPos = MIFParser.mappedTextBuff.position();	//Сохраняем позицию файла (не забываем восстановить потом, чтобы запись в файл пошла по правильному индексу)
			MIFParser.mappedTextBuff.position(offset); //Установим позицию, чтобы прочитать наш объект
			MIFParser.mappedTextBuff.get(btmp, 0, length);
			MIFParser.mappedTextBuff.position(prevPos);	//Восстановили позицию файла
		}
		return btmp;
	}
}
